﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Strategy.cs" company="">
//   
// </copyright>
// <summary>
//   The strategy.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Systemathics.FrameWork.Interfaces;

namespace Systemathics.FrameWork
{
    public abstract class Strategy : IDisposable
    {
        private int DefaultBarSize;
        private StrategyMode Mode;
        private Boolean Disposed;
        private Boolean MakeOnBarOpen;
        private Boolean UnBuilded, Builded;
        private RemotingGraphClient RemoteGraph;
        private Dictionary<Expo, StrategyExposition> StratExpo;
        private BackgroundWorker BackgroundWorkerStrategy;
        private TimeSpan StrategyTimer;
        private TimeSpan? LastCalculationTime;
        private const int BACKTEST_GRANULARITY_IFITCAN = 10;
        private readonly Dictionary<Guid, Object[]> GraphType;
        public RemotingLogClient RemoteLogClient{ private get; set;}
        private decimal CashEquityAtStart;

        public OrderService orderService { get; set; }
        public DataService dataService { get; set; }
        public IFees feesService { get; set; }
        public Dictionary<Guid, Instrument> Instruments { get; private set; }
        public Dictionary<Guid, Order> Orders { get; private set; }
        public Dictionary<String, Dictionary<String, Object>> Params { get; protected set; }
        public StrategyExposition this[Expo style]
        {
            get { return StratExpo[style]; }
            set
            {
                switch (style)
                {
                    case Expo.Theo:
                        StratExpo[Expo.Theo] = value;
                        break;
                }
                return;
            }
        }
        public bool isRunning 
        { get; private set; }
        public bool isPaused 
        { get; set; }
        public bool isConnected
        { get { return dataService.isConnected & orderService.isConnected; } }
        public bool isFlat
        {
            get
            {
                foreach (Instrument i in Instruments.Values)
                    if (!i.isFlat) return false;
                return true;
            }
        }
        public bool isTotallyFlat
        {
            get
            {
                foreach (Instrument i in Instruments.Values)
                    if (!i.isTotallyFlat) return false;
                return true;
            }
        }
        public decimal NetPl_Inventory { get; private set; }
        public decimal NetPl_Traded { get; private set; }
        public TimeSeries ProfitAndLossHistory { get; private set; }
        public double TransactionsCostTraded { get; private set; }
        public double TransactionsCostInventory { get; private set; }
        public double InitialMargin { get; private set; }
        public TimeSpan BuildAt { get; private set; }
        public TimeSpan UnBuildAt { get; private set; }

        public Guid Id { get; private set; }
        public String Name { get; private set; }
        public String Pattern { get; private set; }
        public String Version { get; private set; }
        public String Info { get; private set; }
        public DateTime CreationDate { get; private set; }

        public double MaxDrawDown { get; private set; }
        public double MaxBias { get; private set; }
        public double CashEquity { get; private set; }
        public double Bias { get; private set; }
        public double DrawDown { get; private set; }


        #region Constructor

        protected Strategy()
        {
            isRunning = false;
            UnBuilded = false;
            Builded = false;
            MakeOnBarOpen = false;
            TransactionsCostTraded = 0;
            StrategyTimer = new TimeSpan(0, 0, 0, 1);
            Orders = new Dictionary<Guid, Order>();
            Params = new Dictionary<string, Dictionary<string, object>>();
            GraphType = new Dictionary<Guid, Object[]>();
            StratExpo = new Dictionary<Expo, StrategyExposition>();
        }

        #endregion Constructor

        public DBStrategies Cell
        {
            set
            {
                Id = value.ID;
                Name = value.Name;
                Info = value.Info;
                Pattern = value.Pattern;
                Version = value.Version;
                CreationDate = value.CreationDate;
                MaxBias = value.MaxBias;
                DrawDown = value.MaxDrawDown;
                BuildAt = value.BuildAt;
                UnBuildAt = value.UnBuildAt;
                Instruments = new Dictionary<Guid, Instrument>();
                ProfitAndLossHistory = new TimeSeries(value.Info + "_" + Time.Now.ToFileTime());
                var startTradingDay = DateTime.Today + value.BuildAt;
                var bar = Attribute.GetCustomAttribute(GetType(), typeof(SetBars)) as SetBars;
                DefaultBarSize = 0;
                if (bar != null) DefaultBarSize = bar.Value;
                var excelFile = Attribute.GetCustomAttribute(GetType(), typeof(Parameters)) as Parameters;
                var dictionary = new Dictionary<string, Dictionary<string, object>>();
                if (ProviderFactory.GetParameters(excelFile, value, ref dictionary))
                {
                    if (!value.DBInstruments.IsLoaded)
                        value.DBInstruments.Load();

                    foreach (var dbInstrument in value.DBInstruments)
                    {
                        var i = new Instrument(dbInstrument, dataService, orderService);
                        i.StaticData.Fees = new Fees(dbInstrument, feesService);
                        var inv = new Inventories(i);
                        inv.Inventory(startTradingDay, Id);
                        inv.Traded(startTradingDay, Id);

                        Orders = inv.OpenOrders;
                        orderService.OpenOrders = inv.OpenOrders;

                        Instruments[dbInstrument.ID] = i;
                        Instruments[dbInstrument.ID].OnBlotter += OnStrategyBlotter;
                        Instruments[dbInstrument.ID].OnTrade += OnStrategyTrade;
                        Instruments[dbInstrument.ID].OnMarketData += OnStrategyMarketData;
                        Instruments[dbInstrument.ID].OnOrder += OnStrategyOrders;

                        if (DefaultBarSize > 0 && bar != null)
                        {
                            var b = new Bars(Instruments[dbInstrument.ID], bar.BarType, DefaultBarSize);
                            b.OnBar += OnStrategyBar;
                        }
                        TransactionsCostInventory += Instruments[dbInstrument.ID].StaticData.Fees.TcInventory;
                    }
                    if (dataService.Name == StrategyMode.BackTest.ToString())
                    {
                        Mode = StrategyMode.BackTest;
                        isPaused = false;
                        StrategyTimer = new TimeSpan(0, 0, 0, BACKTEST_GRANULARITY_IFITCAN);
                    }
                    else
                    {
                        if (dataService.Name != StrategyMode.BackTest.ToString() && orderService.Name == StrategyMode.Virtual.ToString())
                            Mode = StrategyMode.Virtual;
                        else
                            Mode = StrategyMode.Live;

                        isPaused = true;
                    }

                    RemoteGraph = new RemotingGraphClient("GraphServer",Id);
                    Params = dictionary;
                    try
                    {
                        dataService.EmitBarSeries += OnStrategyBarSeries;
                        dataService.EmitTradeSeries += OnStrategyTradeSeries;
                        dataService.EmitQuoteSeries += OnStrategyQuoteSeries;
                    }
                    catch (Exception)
                    {
                        Log("No Support for Historical download for this data provider");
                    }
                }
            }
        }


        public void GetHistoricalData(Dictionary<Guid, Instrument> instruments, DateTime begin, DateTime end, Data dt, int? barSize, DataSource ds)
        {
            foreach (Instrument i in instruments.Values) GetHistoricalData(i, begin, end, dt, barSize, ds);
        }
        public void GetHistoricalData(Instrument i, DateTime begin, DateTime end, Data dt, int? barSize, DataSource ds)
        {
            if (dataService.Name.CompareTo(StrategyMode.BackTest.ToString()) == 0) ds = DataSource.CurrentDataProvider;
            if (dataService.isConnected)
            {
                switch (ds)
                {
                    case DataSource.CurrentDataProvider:
                        dataService.GetHistoricalData(begin, end, dt, i.Id, barSize);
                        break;
                    case DataSource.TickCaptureDataBase:
                        try
                        {
                            // What's happen if ticcapture empty or not present ...
                            var backTestProvider = ProviderFactory.GetMixedProvider(StrategyMode.BackTest.ToString(), GlobalVariables.ASSEMBLY);
                            if (backTestProvider != null)
                            {
                                var backTestProviderType = backTestProvider.GetType();
                                var backTestProviderMethod = backTestProviderType.GetMethod("SetDate");
                                backTestProviderMethod.Invoke(backTestProvider, new object[] {begin, end});

                                var newBackTestProvider = backTestProvider as IDataProvider;
                                if (newBackTestProvider != null)
                                {
                                    newBackTestProvider.EmitConnectionStatus += BackTestProviderEmitConnectionStatus;
                                    newBackTestProvider.EmitError += BackTestProviderEmitError;
                                    newBackTestProvider.Connect();

                                    if (newBackTestProvider.isConnected)
                                    {
                                        newBackTestProvider.EmitBarSeries += OnStrategyBarSeries;
                                        newBackTestProvider.EmitTradeSeries += OnStrategyTradeSeries;
                                        newBackTestProvider.EmitQuoteSeries += OnStrategyQuoteSeries;
                                        newBackTestProvider.GetHistoricalData(begin.Date, end.Date, dt, i.Id, barSize);
                                    }
                                }
                            }
                        }
                        catch (Exception e)
                        {
                            RemoteLogClient.Trace(new FireMessageEventArgs(e, DateTime.Now.TimeOfDay));
                        }

                        break;
                }
            }
        }

        private void BackTestProviderEmitError(object sender, FireMessageEventArgs e) 
        { RemoteLogClient.Trace(e); }
        private void BackTestProviderEmitConnectionStatus(object sender, FireMessageEventArgs e) 
        { RemoteLogClient.Trace(e); }
        private void OnStrategyBar(object sender, Bar b)
        {
            OnBarClose(b);
            MakeOnBarOpen = true;

            if (Mode != StrategyMode.BackTest)
                if (GraphType.ContainsKey(b.Id))
                    if ((Data)GraphType[b.Id][0] == Data.Bar)
                        if(b.Median != 0)
                            RemoteGraph.Draw(new GraphEventArgs(b, (double) Instruments[b.Id][Expo.Traded].PL,
                                                                Instruments[b.Id][Expo.Traded].Balance,
                                                                Instruments[b.Id].CustomValue1,
                                                                Instruments[b.Id].CustomValue2)
                                                 {
                                                     CustomValue1Axis = (Axis?) GraphType[b.Id][1],
                                                     CustomValue2Axis = (Axis?) GraphType[b.Id][2]
                                                 });

        }
        private void OnStrategyBarSeries(object sender, BarSeries e) 
        { OnBarSeries(e); }
        private void OnStrategyTradeSeries(object sender, TradeSeries e) 
        { OnTradeSeries(e); }
        private void OnStrategyQuoteSeries(object sender, QuoteSeries e) 
        { OnQuoteSeries(e); }
        private void OnStrategyMarketData(object sender, MarketData e) 
        { if (isRunning) OnMarketData(e); }
        private void OnStrategyTrade(object sender, Trade e)
        {
            if (isRunning)
            {
                OnTrade(e);

                if (MakeOnBarOpen)
                {
                    OnBarOpen(new Bar(Time.Now, Time.Now, e.Price, e.Price, e.Price, e.Price, 0, e.Size, 0){Id = e.Id});
                    MakeOnBarOpen = false;
                }

                if (Mode != StrategyMode.BackTest)
                    if (GraphType.ContainsKey(e.Id))
                        if ((Data)GraphType[e.Id][0] == Data.Trade)
                            if (e.Price != 0)
                                RemoteGraph.Draw(new GraphEventArgs(e , 
                                                                   (double)Instruments[e.Id][Expo.Traded].PL, 
                                                                   Instruments[e.Id][Expo.Traded].Balance, 
                                                                   Instruments[e.Id].CustomValue1, 
                                                                   Instruments[e.Id].CustomValue2)
                                                     {
                                                         CustomValue1Axis = (Axis?)GraphType[e.Id][1], 
                                                         CustomValue2Axis = (Axis?)GraphType[e.Id][2]
                                                     });

            }
        }
        private void OnStrategyBlotter(object sender, Blotter e)
        {
            if (isRunning)
            {
                OnBlotter(e);

                //if (e.TickInfo == TickInfo.Bid_1 || e.TickInfo == TickInfo.Ask_1)
                {
                    if (LastCalculationTime == null)
                        LastCalculationTime = e[QuoteLevel.One].Time.TimeOfDay;
                    else if (e[QuoteLevel.One].Time.TimeOfDay - LastCalculationTime > StrategyTimer)
                    {
                        UpdateStrategyValue(e[QuoteLevel.One].Time);
                        LastCalculationTime = e[QuoteLevel.One].Time.TimeOfDay;
                    }
                    
                    if (Mode != StrategyMode.BackTest)
                        if (GraphType.ContainsKey(e.Id))
                            if ((Data)GraphType[e.Id][0] == Data.Quote)
                                if (e[QuoteLevel.One].Mid != 0)
                                    RemoteGraph.Draw(new GraphEventArgs(e[QuoteLevel.One], 
                                                                       (double)Instruments[e.Id][Expo.Traded].PL, 
                                                                       Instruments[e.Id][Expo.Traded].Balance, 
                                                                       Instruments[e.Id].CustomValue1, 
                                                                       Instruments[e.Id].CustomValue2)              
                                                         {
                                                             CustomValue1Axis = (Axis?)GraphType[e.Id][1], 
                                                             CustomValue2Axis = (Axis?)GraphType[e.Id][2]
                                                         });
                }
            }
        }
        private void OnStrategyOrders(object sender, Order e)
        {
            var o = e.Clone() as Order;
            Orders[o.Id] = o.Clone() as Order;
            OnOrder(o);
        }
        private void UpdateStrategyValue(DateTime calculationtime)
        {
            //if (!BackgroundWorkerStrategy.IsBusy) 
            //    BackgroundWorkerStrategy.RunWorkerAsync(calculationtime);
            test(new DoWorkEventArgs(calculationtime));
        }
        private void BackgroundWorkerStrategyDoWork(object sender, DoWorkEventArgs e){}
        private void test(DoWorkEventArgs e)
        {
            try
            {
                var time = (DateTime)e.Argument;
                if (CashEquity < 0)
                    OnMoneyManagement(new MoneyManagement(CashManagementTrigger.CashEquityNegative, CashEquity));

                Bias = StratExpo[Expo.Inventory].Bias + StratExpo[Expo.Traded].Bias;
                if (Bias > MaxBias)
                    OnMoneyManagement(new MoneyManagement(CashManagementTrigger.MaxBiasTriggered, Bias));

                TransactionsCostTraded = 0;
                InitialMargin = 0;
                foreach (Instrument i in Instruments.Values)
                {
                    TransactionsCostTraded += i.StaticData.Fees.Tc;
                    InitialMargin = i.StaticData.Fees.InitialMargin; // Ponderer par la quantité en pose
                }

                NetPl_Inventory = StratExpo[Expo.Inventory].Realized + StratExpo[Expo.Inventory].UnRealized - new decimal(TransactionsCostInventory);
                NetPl_Traded = StratExpo[Expo.Traded].Realized + StratExpo[Expo.Traded].UnRealized - new decimal(TransactionsCostTraded);
                CashEquity = (double)NetPl_Traded + (double)NetPl_Inventory;  // ?????
                ProfitAndLossHistory.Add(time, CashEquity);

                if (InitialMargin > 0.95 * CashEquity)
                    OnMoneyManagement(new MoneyManagement(CashManagementTrigger.MarginRequirementTriggered, InitialMargin));

                DrawDown = (CashEquity / (double)CashEquityAtStart) - 1;
                if (DrawDown <= MaxDrawDown)
                    OnMoneyManagement(new MoneyManagement(CashManagementTrigger.MaxDrawDownTriggered, DrawDown * 100));

                if (time.TimeOfDay >= BuildAt && time.TimeOfDay <= UnBuildAt && !Builded)
                    OnBuild();
                else if (time.TimeOfDay >= UnBuildAt && !UnBuilded)
                    OnUnBuild();

            }
            catch (Exception ex)
            {
            }
        }

        #region DataService

        public virtual void Draw(Instrument i, Data data, Axis? customValue1Axis, Axis? customValue2Axis)
        {
            var o = i as Object;
            if(o != null)
            {
                if (!GraphType.ContainsKey(i.Id))   // customValue1Axis.HasValue || customValue2Axis.HasValue && 
                    GraphType.Add(i.Id, new Object[] { data ,customValue1Axis,customValue2Axis});
            }
        }
        public virtual void Draw(TimeSeries series)
        {
            if (RemoteGraph != null)
                RemoteGraph.DrawHistory(new GraphEventArgs(series));
        }
        public virtual void Draw(QuoteSeries series)
        {
            if (RemoteGraph != null)
                RemoteGraph.DrawHistory(new GraphEventArgs(series));
        }
        public virtual void Draw(TradeSeries series)
        {
            if (RemoteGraph != null)
                RemoteGraph.DrawHistory(new GraphEventArgs(series));
        }
        public virtual void Draw(BarSeries series)
        {
            if (RemoteGraph != null)
                RemoteGraph.DrawHistory(new GraphEventArgs(series));
        }

        public virtual void Log(string message) 
        { RemoteLogClient.Trace(new FireMessageEventArgs(message, Time.Now.TimeOfDay)); }
        public virtual void OnBuild()
        {
            Builded = true;
            Log("On Build started: Strategy " + Name + " - Info: " + Info);
        }
        public virtual void OnUnBuild()
        {
            UnBuilded = true;
            Log("On UnBuild started: Strategy " + Name + " - Info: " + Info);
        }
        public virtual void OnQuoteSeries(QuoteSeries series) { }
        public virtual void OnTradeSeries(TradeSeries series) { }
        public virtual void OnBarSeries(BarSeries series) { }
        public virtual void OnBarClose(Bar bar) { }
        public virtual void OnBarOpen(Bar bar) { }
        public virtual void OnMarketData(MarketData marketdata) { }
        public virtual void OnTrade(Trade trade) { }
        public virtual void OnBlotter(Blotter blotter) { }
        public virtual void OnOrder(Order order) { }
        public virtual void OnMoneyManagement(MoneyManagement mm)
        {
            Log("Strategy: " + Name + " Info: " + Info + " -  Money Management Rule Triggered: " + mm.Reason + " Amount :" + mm.Amount);
        }

        #endregion 

        #region OrderService

        public Guid Buy(Guid id, OrderStyle style, Decimal price, int quantity, OrderExtension ext)
        {
            if (!isPaused)
                return Instruments[id].Buy(style, price, quantity, ext, Id);
            Log("Strategy " + Name + " has been Paused and cannot Buy " + Instruments[id].StaticData.Name);
            return new Guid();
        }
        public void BuyBracket(Guid id, int quantity, Decimal takeProfit,  Decimal stopLosss)
        {
            if (!isPaused)
                Instruments[id].Bracket(OrderSide.Buy, quantity, takeProfit, stopLosss, Id);
            Log("Strategy " + Name + " has been Paused and cannot Buy " + Instruments[id].StaticData.Name);
        }

        public Guid Sell(Guid id, OrderStyle style, Decimal price, int quantity, OrderExtension ext)
        {
            if (!isPaused)
                return Instruments[id].Sell(style, price, quantity, ext, Id);
            Log("Strategy " + Name + " has been Paused and cannot Sell " + Instruments[id].StaticData.Name);
            return new Guid();
        }
        public void SellBracket(Guid id, int quantity, Decimal takeProfit, Decimal stopLosss)
        {
            if (!isPaused)
                Instruments[id].Bracket(OrderSide.Sell, quantity, takeProfit, stopLosss, Id);
            Log("Strategy " + Name + " has been Paused and cannot Buy " + Instruments[id].StaticData.Name);
        }

        public bool Modify(Guid orderId, int newQty)
        {
            if (Orders.ContainsKey(orderId))
            {
                var instrumenId = Orders[orderId].InstrumentId;
                if (!isPaused)
                    return Instruments[instrumenId].Modify(orderId, newQty);
                Log("Strategy " + Name + " has been Paused and cannot Modify Order on" + Instruments[instrumenId].StaticData.Name);
            }
            else
                Log("Strategy: " + Name + " - " + orderId + "OrdeId doesn't correspond to any Orders Handled by this strategy");

            return false;
        }
        public bool Modify(Guid orderId, Decimal newPrice)
        {
            if (Orders.ContainsKey(orderId))
            {
                var instrumenId = Orders[orderId].InstrumentId;
                if (!isPaused)
                    return Instruments[instrumenId].Modify(orderId, newPrice);
                Log("Strategy " + Name + " has been Paused and cannot Modify Order on" + Instruments[instrumenId].StaticData.Name);
            }
            else
                Log("Strategy: " + Name + " - " + orderId + "OrdeId doesn't correspond to any Orders Handled by this strategy");

            return false;
        }
        public bool Modify(Guid orderId, Decimal newPrice, int newQty)
        {
            if (Orders.ContainsKey(orderId))
            {
                var instrumenId = Orders[orderId].InstrumentId;
                if (!isPaused)
                    return Instruments[instrumenId].Modify(orderId, newPrice, newQty);
                Log("Strategy " + Name + " has been Paused and cannot Modify Order on" + Instruments[instrumenId].StaticData.Name);
            }
            else
                Log("Strategy: " + Name + " - " + orderId + "OrdeId doesn't correspond to any Orders Handled by this strategy");

            return false;
        }

        public bool Cancel(Guid orderId)
        {
            if (Orders.ContainsKey(orderId))
            {
                var instrumenId = Orders[orderId].InstrumentId;
                if (!isPaused)
                    return Instruments[instrumenId].Cancel(orderId);
                Log("Strategy " + Name + " has been Paused and cannot Cancel Order on" + Instruments[instrumenId].StaticData.Name);
            }
            else
                Log("Strategy: " + Name + " - " + orderId + "OrdeId doesn't correspond to any Orders Handled by this strategy");

            return false;
        }
        public int  CancelAllStrategyOrders()
        {
            var n = 0;
            if (!isPaused)
            {
                foreach (Instrument i in Instruments.Values)
                    n += i.CancelAllOrders();
                Log("Strategy " + Name + " has sent " + n + " Cancel requests");
            }
            else
                Log("Strategy " + Name + " has been Paused and cannot Cancel Order All Strategy Orders");
            return n;
        }
        public int  CancelAllStrategyBuyOrders()
        {
            var n = 0;
            if (!isPaused)
            {
                foreach (Instrument i in Instruments.Values)
                    n += i.CancelAllBuyOrders();
                Log("Strategy " + Name + " has sent " + n + " Cancel requests");
            }
            else
                Log("Strategy " + Name + " has been Paused and cannot Cancel Order All Strategy Buy Orders");
            return n;
        }
        public int  CancelAllStrategySellOrders()
        {
            var n = 0;
            if (!isPaused)
            {
                foreach (Instrument i in Instruments.Values)
                    n += i.CancelAllSellOrders();
                Log("Strategy " + Name + " has sent " + n + " Cancel requests");
            }
            else
                Log("Strategy " + Name + " has been Paused and cannot Cancel Order All Strategy Sell Orders");
            return n;
        }

        public void SweepToFill(Expo expo)
        {
            if (!isPaused)
            {
                foreach (Instrument i in Instruments.Values)
                    i.SweepToFill(expo, Id);
            }
            else
                Log("Strategy " + Name + " has been Paused and cannot Flatten All Strategy Traded Orders");
        }
        public bool ReSend(Guid orderId)
        {
            if (Orders.ContainsKey(orderId))
            {
                var instrumenId = Orders[orderId].InstrumentId;
                if (!isPaused)
                    return Instruments[instrumenId].ReSend(orderId);
                Log("Strategy " + Name + " has been Paused and cannot ReSend Order on" + Instruments[instrumenId].StaticData.Name);
            }
            else
                Log("Strategy: " + Name + " - " + orderId + "OrdeId doesn't correspond to any Orders Handled by this strategy");

            return false;
        }
   
        #endregion OrderService

        public virtual void OnStart()
        {
            // Check the fact that all suscription events succeed (there is no stock unsuscribed among all for example)
            if (Instruments.Count() > 0)
            {
                foreach (KeyValuePair<Guid, Instrument> instrument in Instruments)
                    instrument.Value.Suscribe();

                // N.B : On initie seulement une foie,
                // il ne faut pas reinititier a chaque fois que tu restart la strategy, tu peust start/stoper plusieurs fois dans la journée
                // quand tu restart tu est content de garder dans tes expo, tous les inventory qui on lourdement ete calculés dans Set_StrategyCell
                // ainsi que les traded de la journée.

                if (StratExpo.Count == 0)
                {
                    foreach (Expo expo in Enum.GetValues(typeof(Expo)))
                    StratExpo[expo] = new StrategyExposition(Instruments.Values.ToArray(), expo);
                }
              
                BackgroundWorkerStrategy = new BackgroundWorker();
                BackgroundWorkerStrategy.DoWork += BackgroundWorkerStrategyDoWork;
                CashEquityAtStart = (decimal)CashEquity;
                
                isRunning = true;
            }
            else 
                isRunning = false;
        }
        public virtual void OnStop()
        {
            if (isRunning)
            {
                if (Mode != StrategyMode.BackTest)
                {
                    using (var db = new SystemathicsEntities(GlobalVariables.EntitiesConnectionString()))
                    {
                        db.DBStrategies.Where(u => u.ID == Id).FirstOrDefault().CashEquity = CashEquity;
                        db.SaveChanges(true);
                    }
                }
                else
                {
                    if(ProfitAndLossHistory.Count() > 0)
                    {
                        var oe = new ToExcel("Backtest_" + Time.Now.ToFileTime()) { WorkSheetName = "Orders_" + Time.Now.ToFileTime()};
                        oe.Add(Orders);
                        oe.WorkSheetName = "P&L_" + Time.Now.ToFileTime();
                        oe.Add(ProfitAndLossHistory);
                        oe.Flush();
                        oe.Close();
                        RemoteGraph.DrawHistory(new GraphEventArgs(ProfitAndLossHistory));
                    }
                }

                try
                {
                    dataService.EmitBarSeries -= OnStrategyBarSeries;
                    dataService.EmitTradeSeries -= OnStrategyTradeSeries;
                    dataService.EmitQuoteSeries -= OnStrategyQuoteSeries;
                }
                catch (Exception)
                {
                }
                foreach (KeyValuePair<Guid, Instrument> kvp in Instruments)
                {
                    kvp.Value.OnBlotter -= OnStrategyBlotter;
                    kvp.Value.OnTrade -= OnStrategyTrade;
                    kvp.Value.OnMarketData -= OnStrategyMarketData;
                    kvp.Value.OnOrder -= OnStrategyOrders;
                    kvp.Value.Unsubscribe();
                    
                    kvp.Value.Orders.Clear();
                    
                    //kvp.Value.Dispose();

                }

                // Ne pas effacer cf NOTA BENE
                //foreach (Expo expo in Enum.GetValues(typeof(Expo)))
                //    StratExpo[expo].Init();

                //this.NetPl_Inventory = 0;
                //this.NetPl_Traded = 0;
                //this.TransactionsCostTraded = 0;
                //this.TransactionsCostInventory = 0;

                BackgroundWorkerStrategy.DoWork -= BackgroundWorkerStrategyDoWork;
                GraphType.Clear();
                LastCalculationTime = null;
                isRunning = false;
            }
        }

        #region IDisposable 

        public void Dispose()
        {
            Dispose(true);
        }
        protected void Dispose(bool disposing)
        {
            if (!Disposed)
            {
                if (disposing)
                {
                    GC.SuppressFinalize(this);
                    StratExpo = null;
                    Instruments = null;
                    Orders = null;
                    RemoteGraph = null;
                }
            }

            Disposed = true;
        }

        #endregion IDisposable
    }
}